const { fetchRepoList, fetchTagList } = require("./request");
const Inquirer = require("inquirer");
const downloadGitRepo = require("download-git-repo");
const util = require("util");
const path = require("path");
const fs = require("fs");
const { wrapLoading } = require("./util");
class Creator {
  constructor(projectName, targetDir) {
    this.name = projectName;
    this.target = targetDir;
    this.downloadGitRepo = util.promisify(downloadGitRepo);
  }
  async fetchRepo() {
    // 失败重新拉取
    let repos = await wrapLoading(fetchRepoList, "waiting fetch template");
    if (!repos) return;
    repos = repos.map((item) => item.name);
    let { repo } = await Inquirer.prompt({
      name: "repo",
      type: "list",
      choices: repos,
      message: "please choose a template to create project:",
    });
    return repo;
  }
  async fetchTag(repo) {
    let tags = await wrapLoading(fetchTagList, "waiting fetch tag", repo);
    if (!tags) return;
    let { tag } = await Inquirer.prompt({
      name: "tag",
      type: "list",
      choices: tags,
      message: "please choose a tag to create project:",
    });
    return tag;
  }
  async download(repo, tag) {
    // 1. 需要拼接出下载路径来
    // yanyunchangfeng/vue-template#1.0
    let requestUrl = `yanyunchangfeng/${repo}${tag ? "#" + tag : ""}`;
    // 2. 把资源下载到某个路径上（后续可以增加缓存功能,应该下载到系统目录中，稍后可以再使用ejs handlerbar 去渲染模版 最后生成结果 再写入）

    // 放到系统文件中 -> 模版和 用户的其他选择 => 生成结果 放到当前目录下
    // await this.downloadGitRepo(requestUrl, path.resolve(process.cwd(), `${repo}@${tag}`))
    // await wrapLoading(this.downloadGitRepo, 'waiting for download', requestUrl, path.resolve(process.cwd(), `${repo}@${tag}`))
    await wrapLoading(
      this.downloadGitRepo,
      "waiting for download",
      requestUrl,
      this.target
    );
    return this.target;
  }
  exec(command, args, description) {
    console.log(`setup:${description}`);
    return new Promise((resolve, reject) => {
      let cp = require("child_process").spawn(command, args, {
        cwd: this.target,
        stdio: "inherit",
        shell: true,
      });
      cp.on("error", (error) => {
        reject(new Error(`${description} failed with ${error}`));
      });
      cp.on("exit", (exitCode) => {
        if (exitCode) {
          reject(`${description} failed with code ${exitCode}`);
        } else {
          resolve();
        }
      });
    });
  }
  writeConfig() {
    const packageJson = path.join(this.target, "package.json");
    let pInfo = fs.readFileSync(packageJson, "utf-8");
    pInfo = JSON.parse(pInfo);
    pInfo.name = this.name;
    fs.writeFileSync(
      packageJson,
      JSON.stringify(pInfo, null, 2) + require("os").EOL
    );
  }
  async create() {
    // 真实开始创建了
    // 采用远程拉取的方式 github
    // 2). 我们要实现脚手架 先做一个命令行交互的功能 inquirer
    // 3). 将模版下载下来 download-git-repo
    // 4). 根据用户的选择动态的生成内容 metalsmith

    // 1.先去拉取当前组织下的模版
    let repo = await this.fetchRepo();
    // console.log(repo, 'repo')
    // 2. 再通过模版找到版本号
    let tag = await this.fetchTag(repo);
    //3 下载模版
    await this.download(repo, tag);
    // 更改package.json信息
    await this.writeConfig();
    // 下载依赖
    await this.exec("yarn", [], "Install Dependencies");

    //4 编译模版
  }
}
module.exports = Creator;
